package Game
{
	import Box2D.Collision.Shapes.b2PolygonShape;
	import Box2D.Dynamics.b2Body;
	import Box2D.Dynamics.b2BodyDef;
	import Box2D.Dynamics.b2FixtureDef;
	import Common.Utils;
	import flash.net.FileReference;
	import flash.net.URLLoaderDataFormat;
	import flash.net.URLRequestHeader;
	import flash.utils.ByteArray;
	import flash.utils.Endian;
	import flash.utils.getDefinitionByName;
	import flash.utils.getQualifiedClassName;
	import Game.GameElements.GameObject;
	import Game.GameElements.Wall;

	import flash.display.DisplayObject;
	import flash.display.MovieClip;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	import flash.net.URLLoader;
	import flash.net.URLRequest;
	
	import Common.Managers.SwfManager;
	
	import Game.GameStates.GameState;
	/**
	 * ...
	 * @author 
	 */
	public class World extends Sprite
	{
		private static var	m_currentLevel:int 			= 1;
		private static var  m_onInitHandler:Function	= null;
		
		private var 		m_backgroundLayer:Sprite 	= null;
		private var 		m_objectLayer:Sprite	 	= null;
		private var 		m_foregroundLayer:Sprite 	= null;
		
		private var 		m_zoomIndx:Number 			= 1;
		
		private static const s_instance:World 			= new World();
		
		public function World() 
		{
			if (s_instance == null)
			{
				trace ("World initialized");
			}
			else
			{
				trace("ERROR: Already existing instance in Singleton");
				throw new Error("Already existing instance in Singleton");
			}
		}
		
		public static function get instance():World
		{
			return s_instance;
		}
		
		// Initialize
		public function initialize(level:int, onInitHandler:Function, isEditor:Boolean = false):void
		{
			s_instance.release();
			// Add to main sprite
			m_backgroundLayer = new Sprite();
			m_objectLayer = new Sprite();
			m_foregroundLayer = new Sprite();
			Main.mainSprite.addChild(m_backgroundLayer);
			Main.mainSprite.addChild(m_objectLayer);
			Main.mainSprite.addChild(m_foregroundLayer);
			
			if (!isEditor)
			{
				m_currentLevel = level;
				m_onInitHandler = onInitHandler;
			
				loadLevel(Settings.pathRes + "levels/level.data");
			}
		}
					
		public function release():void
		{
			if (m_backgroundLayer != null)
			{
				while (m_backgroundLayer.numChildren) m_backgroundLayer.removeChildAt(0);
			}
			if (m_objectLayer != null)
			{
				while (m_objectLayer.numChildren) m_objectLayer.removeChildAt(0);
			}
			if (m_foregroundLayer != null)
			{
				while (m_foregroundLayer.numChildren) m_foregroundLayer.removeChildAt(0);
			}
			
			m_backgroundLayer = null;
			m_objectLayer = null;
			m_foregroundLayer = null;			
			m_onInitHandler = null;
		}
		
		public function get objectLayer():Sprite
		{
			return m_objectLayer;
		}
		
		public function get backgroundLayer():Sprite
		{
			return m_backgroundLayer;
		}
		
		public function get foregroundLayer():Sprite
		{
			return m_foregroundLayer;
		}
		
		public function zoomIn():void
		{
			m_zoomIndx *= 1.1;
			zoom(m_zoomIndx);
		}
		
		public function zoomOut():void
		{
			m_zoomIndx *= 0.9;
			zoom(m_zoomIndx);
		}
		
		public function zoom100():void
		{
			m_zoomIndx = 1;
			zoom(m_zoomIndx);
		}
		
		public function zoom(value:Number):void
		{
			scaleX = value;
			scaleY = value;
			
			Main.mainSprite.scaleX = value;
			Main.mainSprite.scaleY = value;
		}
		
		public function saveLevel():void
		{
			var file:FileReference = new FileReference();
			var data:ByteArray = new ByteArray();
						
			data.writeInt(GameObject.gameObjects.length);
			for each(var object:GameObject in GameObject.gameObjects)
			{				
				data.writeUTF(getQualifiedClassName(object));
				object.serialize(data);
				data.writeUTF("\n");
			}
			
			file.save(data, 'level.txt');
		}
		
		public function loadLevel(level:String = null):void
		{
			for (var i:int = GameObject.gameObjects.length - 1; i >= 0; --i)
			{
				var object:GameObject = GameObject.gameObjects[i] as GameObject;
				object.release();
			}
			
			if (level == null)
			{
				var file:FileReference = new FileReference();
				file.addEventListener(Event.SELECT, onSelect);
				file.addEventListener(Event.COMPLETE, onLoad);
				file.browse();
			}
			else
			{
				var loader:URLLoader = new URLLoader();
				var request:URLRequest = new URLRequest(level);
				loader.dataFormat = URLLoaderDataFormat.BINARY;
				
				var header:URLRequestHeader = new URLRequestHeader("pragma", "no-cache");
				request.requestHeaders.push(header);
				
				loader.addEventListener(Event.COMPLETE, onLoad);
				//loader.addEventListener(IOErrorEvent.IO_ERROR, onBinaryDataIOError);
				loader.load(request);
			}
									
			function onSelect(e:Event):void
			{				
				file.load();
			}
			function onLoad(e:Event):void
			{
				var data:ByteArray;
				if (level != null)
				{
					data = e.currentTarget.data as ByteArray;
				}
				else
				{
					data = file.data;
				}
				createFromByteArray(data);
				
				if (m_onInitHandler != null)
				{
					m_onInitHandler();
				}
			}
		}
		
		public function createFromByteArray(data:ByteArray):void
		{
			var numObject:int = data.readInt();
			for (var i:int = 0; i < numObject; ++i)
			{
				var className:String = data.readUTF();
				var objClass:Object = getDefinitionByName(className);
				var object:GameObject = objClass.deserialize(data);
				object.isFreeze = true;
				data.readUTF();
			}
		}
	}
}